package controller

import (
	"beergo/app/sys/elog"
	"beergo/conf/const/code"
	"beergo/lib/base/orm"
	"beergo/lib/logger"
	"beergo/lib/tool"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"reflect"
	"strings"
	"sync"
	"time"

	//"fmt"
	//"github.com/astaxie/beego/logs"
	"github.com/beego/beego/v2/server/web"
	_ "github.com/go-sql-driver/mysql"
)

type BaseController struct {
	web.Controller
	orm.BaseOrm
	JsonData map[string]interface{}
}

var mutex sync.Mutex

func init() {

}
func (this *BaseController) Prepare() {
	this.JsonData = map[string]interface{}{}
}
func (this *BaseController) CheckAccessToken() string {
	//this.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", this.Ctx.Request.Header.Get("Origin"))
	AccessTokenKey := web.AppConfig.DefaultString("beer::AccessToken","Access-Token")
	frontAT := this.Ctx.Input.Header(AccessTokenKey)
	if frontAT == "" {
		//重新生成一个access-token
		frontAT = tool.Md5("frontAT" + string(rand.Int()) + string(time.Now().Unix()) + "ht")
	}
	this.Ctx.ResponseWriter.Header().Set(AccessTokenKey, frontAT)
	return frontAT
}

func (this *BaseController) JsonOut(status int, message string, data interface{}) {
	this.CheckAccessToken()
	this.Data["json"] = map[string]interface{}{
		"s": status,
		"i": message,
		"d": data,
	}
	this.HandleErrors(this.ServeJSON())
	go HttpLogger(this)
}

func (this BaseController) SuccessJson(message string, data interface{}) {
	this.JsonOut(1, message, data)
}

func (this BaseController) ErrorJson(message string, data interface{}) {
	this.JsonOut(0, message, data)
	this.StopRun()
}

func (this *BaseController) ReturnSuccess(message string, data interface{}) {
	this.CheckAccessToken()
	this.Data["json"] = map[string]interface{}{
		"code": code.Success,
		"msg":  message,
		"data": data,
	}
	this.HandleErrors(this.ServeJSON())
	go HttpLogger(this)
}
func (this *BaseController) Html(content string) {
	this.Ctx.ResponseWriter.Write([]byte(content))
	this.StopRun()
}

func (this *BaseController) ReturnString(body string) {
	this.CheckAccessToken()
	var data map[string]interface{}
	e := json.Unmarshal([]byte(body), &data)
	if e != nil {
		this.StopError(code.ErrorServer, "数据解析错误", "ReturnString")
	} else {
		this.Data["json"] = data
	}
	this.HandleErrors(this.ServeJSON())
	go HttpLogger(this)
}

func (this *BaseController) ReturnError(code int, message string, data interface{}) {
	this.CheckAccessToken()
	this.Data["json"] = map[string]interface{}{
		"code": code,
		"msg":  message,
		"data": data,
	}
	this.HandleErrors(this.ServeJSON())
	go HttpLogger(this)
}

func (this BaseController) StopError(code int, message string, data interface{}) {
	this.ReturnError(code, message, data)
	this.StopRun()
}

func (this BaseController) CheckModelFound(id int, message string) {
	if id == 0 {
		this.StopError(code.ErrorNotFound, message, id)
	}
}

func (this BaseController) AnaliseErrors(err error) {
	if err != nil {
		elog.AddLog(err,2)
		this.StopError(5000, err.Error(), "错误原因")
	}
}
func (this BaseController) TryError(err error) {
	this.AnaliseErrors(err)
}

//获取未知格式body传参
func (this BaseController) GetBodyParam(name string) interface{} {
	var data map[string]interface{}
	this.Try(json.Unmarshal(this.Ctx.Input.RequestBody, &data))
	return data[name]
}
func (this BaseController) GetBodyParamMap(name string) map[string]interface{} {
	var data map[string]map[string]interface{}
	this.Try(json.Unmarshal(this.Ctx.Input.RequestBody, &data))
	return data[name]
}
func (this BaseController) GetBodyParamSlice(name string) []interface{} {
	var data map[string][]interface{}
	this.Try(json.Unmarshal(this.Ctx.Input.RequestBody, &data))
	return data[name]
}
func (this BaseController) GetBodyParamSliceString(name string) []string {
	var data map[string][]string
	this.Try(json.Unmarshal(this.Ctx.Input.RequestBody, &data))
	return data[name]
}
func (this BaseController) GetBodyParamAll() map[string]interface{} {
	var data map[string]interface{}
	this.Try(json.Unmarshal(this.Ctx.Input.RequestBody, &data))
	return data
}
func (this BaseController) GetBodyParamIntSlice(name string) []int {
	var data map[string]interface{}
	this.Try(json.Unmarshal(this.Ctx.Input.RequestBody, &data))
	tmp, ok := data[name]
	if ok {
		t := reflect.TypeOf(tmp)
		if t.String() == "[]interface {}" {
			ids := make([]int, 0)
			for _, test := range tmp.([]interface{}) {
				id, ok := test.(float64)
				if ok {
					ids = append(ids, int(id))
				}
			}
			return ids
		}
	}
	return make([]int, 0)
}

//获取Body传参Int格式
func (this BaseController) GetBodyParamInt(name string) int {
	value, err := this.GetInt(name)
	if err == nil {
		return value
	}

	var data map[string]int
	json.Unmarshal(this.Ctx.Input.RequestBody, &data)
	return data[name]
}

func (this BaseController) GetBodyParamBool(name string) bool {
	var data map[string]bool
	this.Try(json.Unmarshal(this.Ctx.Input.RequestBody, &data))
	//this.LogOut(data)
	return data[name]
}

//获取Body传参Int格式
func (this BaseController) GetBodyParamString(name string) string {
	value := this.GetString(name)
	if value != "" {
		return value
	}
	var data map[string]string
	json.Unmarshal(this.Ctx.Input.RequestBody, &data)
	return data[name]
}

func (this BaseController) GetConfigString(str string) string {
	data, _ := web.AppConfig.String(str)
	return data
}

func (this BaseController) GetConfigBool(str string) bool {
	data, _ := web.AppConfig.Bool(str)
	return data
}

func (this BaseController) GetConfigInt(str string) int {
	data, _ := web.AppConfig.Int(str)
	return data
}

func HttpLogger(c *BaseController) {
	defer mutex.Unlock()
	mutex.Lock()
	//dev := web.AppConfig.DefaultString("runmode", "prod")
	ApiLog := web.AppConfig.DefaultBool("ApiLog", false)
	if ApiLog {
		return
	}
	ctx := c.Ctx
	inputContent := `
****************Input**************************
from:%s		to:%s
URL:
	%s
POST_DATA:
	%s
BODY:
	%s
POST_GET_DATA:
	%s
HEADER:
	authorization：%s
	X-AUTH-TOKEN：%s
	access-token：%s
	a-auth-token：%s
****************Output**************************`
	inputContent = fmt.Sprintf(inputContent,
		ctx.Input.IP(),
		ctx.Input.Host(),
		ctx.Input.URL(),
		ctx.Request.PostForm,
		string(ctx.Input.RequestBody),
		ctx.Request.Form,
		ctx.Input.Header("authorization"),
		ctx.Input.Header("X-AUTH-TOKEN"),
		ctx.Input.Header("access-token"),
		ctx.Input.Header("a-auth-token"),
	)
	out := c.Data["json"]
	outStr, _ := json.MarshalIndent(out, "", "	")
	api := strings.ReplaceAll(ctx.Input.URL(), "/", "")
	//tmpFile:= "/var/debug/" + tool.GetDate("")+"/"+tool.Md5(fmt.Sprintf("%d%s%s",time.Now().UnixNano(),ctx.Input.URL(),ctx.Input.IP())) + ".log"
	tmpFile := "/var/debug/" + tool.GetDate("") + "/" + tool.GetTime("") +  api + ".log"
	root, _ := os.Getwd()
	root = strings.ReplaceAll(root, "\\", "/")
	tool.CreateDirForPath(root + tmpFile)
	err := ioutil.WriteFile(root+tmpFile, []byte(inputContent+"\r\n"+string(outStr)), 0777)
	if err != nil {
		println("http 日志写入错误")
	}
	//time.Sleep(100 * time.Millisecond)

	logger.ColorPrintStart(223)
	print("[LOGFile]")
	logger.ColorPrintEnd()
	println(fmt.Sprintf(" %s%s:1\t", root, tmpFile))
}
